From a75d995bd4f168733e30f5177b8fbf37e48d2813 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 22 Sep 2017 14:20:57 -0400 Subject: [PATCH] vulkan: Implement crossfade This is the first shader using two textures. It almost works. --- gsk/gskvulkancrossfadepipeline.c | 146 ++++++++++++++++++ gsk/gskvulkancrossfadepipelineprivate.h | 35 +++++ gsk/gskvulkanpipelineprivate.h | 1 - gsk/gskvulkanrender.c | 4 + gsk/gskvulkanrenderpass.c | 122 ++++++++++++++- gsk/gskvulkanrenderprivate.h | 3 + gsk/meson.build | 1 + .../vulkan/crossfade-clip-rounded.frag.spv | Bin 0 -> 8720 bytes .../vulkan/crossfade-clip-rounded.vert.spv | Bin 0 -> 5840 bytes gsk/resources/vulkan/crossfade-clip.frag.spv | Bin 0 -> 1780 bytes gsk/resources/vulkan/crossfade-clip.vert.spv | Bin 0 -> 5840 bytes gsk/resources/vulkan/crossfade-rect.vert.spv | Bin 0 -> 5840 bytes gsk/resources/vulkan/crossfade.frag | 21 +++ gsk/resources/vulkan/crossfade.frag.spv | Bin 0 -> 1780 bytes gsk/resources/vulkan/crossfade.vert | 44 ++++++ gsk/resources/vulkan/crossfade.vert.spv | Bin 0 -> 4108 bytes gsk/resources/vulkan/meson.build | 2 + 17 files changed, 373 insertions(+), 6 deletions(-) create mode 100644 gsk/gskvulkancrossfadepipeline.c create mode 100644 gsk/gskvulkancrossfadepipelineprivate.h create mode 100644 gsk/resources/vulkan/crossfade-clip-rounded.frag.spv create mode 100644 gsk/resources/vulkan/crossfade-clip-rounded.vert.spv create mode 100644 gsk/resources/vulkan/crossfade-clip.frag.spv create mode 100644 gsk/resources/vulkan/crossfade-clip.vert.spv create mode 100644 gsk/resources/vulkan/crossfade-rect.vert.spv create mode 100644 gsk/resources/vulkan/crossfade.frag create mode 100644 gsk/resources/vulkan/crossfade.frag.spv create mode 100644 gsk/resources/vulkan/crossfade.vert create mode 100644 gsk/resources/vulkan/crossfade.vert.spv diff --git a/gsk/gskvulkancrossfadepipeline.c b/gsk/gskvulkancrossfadepipeline.c new file mode 100644 index 0000000000..a0de8c3d56 --- /dev/null +++ b/gsk/gskvulkancrossfadepipeline.c @@ -0,0 +1,146 @@ +#include "config.h" + +#include "gskvulkancrossfadepipelineprivate.h" + +struct _GskVulkanCrossFadePipeline +{ + GObject parent_instance; +}; + +typedef struct _GskVulkanCrossFadeInstance GskVulkanCrossFadeInstance; + +struct _GskVulkanCrossFadeInstance +{ + float rect[4]; + float start_tex_rect[4]; + float end_tex_rect[4]; + float progress; +}; + +G_DEFINE_TYPE (GskVulkanCrossFadePipeline, gsk_vulkan_cross_fade_pipeline, GSK_TYPE_VULKAN_PIPELINE) + +static const VkPipelineVertexInputStateCreateInfo * +gsk_vulkan_cross_fade_pipeline_get_input_state_create_info (GskVulkanPipeline *self) +{ + static const VkVertexInputBindingDescription vertexBindingDescriptions[] = { + { + .binding = 0, + .stride = sizeof (GskVulkanCrossFadeInstance), + .inputRate = VK_VERTEX_INPUT_RATE_INSTANCE + } + }; + static const VkVertexInputAttributeDescription vertexInputAttributeDescription[] = { + { + .location = 0, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = 0, + }, + { + .location = 1, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, start_tex_rect), + }, + { + .location = 2, + .binding = 0, + .format = VK_FORMAT_R32G32B32A32_SFLOAT, + .offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, end_tex_rect), + }, + { + .location = 3, + .binding = 0, + .format = VK_FORMAT_R32_SFLOAT, + .offset = G_STRUCT_OFFSET (GskVulkanCrossFadeInstance, progress), + } + }; + static const VkPipelineVertexInputStateCreateInfo info = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .vertexBindingDescriptionCount = G_N_ELEMENTS (vertexBindingDescriptions), + .pVertexBindingDescriptions = vertexBindingDescriptions, + .vertexAttributeDescriptionCount = G_N_ELEMENTS (vertexInputAttributeDescription), + .pVertexAttributeDescriptions = vertexInputAttributeDescription + }; + + return &info; +} + +static void +gsk_vulkan_cross_fade_pipeline_finalize (GObject *gobject) +{ + //GskVulkanCrossFadePipeline *self = GSK_VULKAN_BLUR_PIPELINE (gobject); + + G_OBJECT_CLASS (gsk_vulkan_cross_fade_pipeline_parent_class)->finalize (gobject); +} + +static void +gsk_vulkan_cross_fade_pipeline_class_init (GskVulkanCrossFadePipelineClass *klass) +{ + GskVulkanPipelineClass *pipeline_class = GSK_VULKAN_PIPELINE_CLASS (klass); + + G_OBJECT_CLASS (klass)->finalize = gsk_vulkan_cross_fade_pipeline_finalize; + + pipeline_class->get_input_state_create_info = gsk_vulkan_cross_fade_pipeline_get_input_state_create_info; +} + +static void +gsk_vulkan_cross_fade_pipeline_init (GskVulkanCrossFadePipeline *self) +{ +} + +GskVulkanPipeline * +gsk_vulkan_cross_fade_pipeline_new (GdkVulkanContext *context, + VkPipelineLayout layout, + const char *shader_name, + VkRenderPass render_pass) +{ + return gsk_vulkan_pipeline_new (GSK_TYPE_VULKAN_CROSS_FADE_PIPELINE, context, layout, shader_name, render_pass); +} + +gsize +gsk_vulkan_cross_fade_pipeline_count_vertex_data (GskVulkanCrossFadePipeline *pipeline) +{ + return sizeof (GskVulkanCrossFadeInstance); +} + +void +gsk_vulkan_cross_fade_pipeline_collect_vertex_data (GskVulkanCrossFadePipeline *pipeline, + guchar *data, + const graphene_rect_t *bounds, + const graphene_rect_t *start_bounds, + const graphene_rect_t *end_bounds, + double progress) +{ + GskVulkanCrossFadeInstance *instance = (GskVulkanCrossFadeInstance *) data; + + instance->rect[0] = bounds->origin.x; + instance->rect[1] = bounds->origin.y; + instance->rect[2] = bounds->size.width; + instance->rect[3] = bounds->size.height; + + instance->start_tex_rect[0] = (bounds->origin.x - start_bounds->origin.x)/start_bounds->size.width; + instance->start_tex_rect[1] = (bounds->origin.y - start_bounds->origin.y)/start_bounds->size.height; + instance->start_tex_rect[2] = (bounds->size.width + bounds->origin.x - start_bounds->origin.x)/start_bounds->size.width; + instance->start_tex_rect[3] = (bounds->size.height + bounds->origin.y - start_bounds->origin.y)/start_bounds->size.height; + + instance->end_tex_rect[0] = (bounds->origin.x - end_bounds->origin.x)/end_bounds->size.width; + instance->end_tex_rect[1] = (bounds->origin.y - end_bounds->origin.y)/end_bounds->size.height; + instance->end_tex_rect[2] = (bounds->size.width + bounds->origin.x - end_bounds->origin.x)/end_bounds->size.width; + instance->end_tex_rect[3] = (bounds->size.height + bounds->origin.y - end_bounds->origin.y)/end_bounds->size.height; + + instance->progress = progress; +} + +gsize +gsk_vulkan_cross_fade_pipeline_draw (GskVulkanCrossFadePipeline *pipeline, + VkCommandBuffer command_buffer, + gsize offset, + gsize n_commands) +{ + vkCmdDraw (command_buffer, + 6, n_commands, + 0, offset); + + return n_commands; +} diff --git a/gsk/gskvulkancrossfadepipelineprivate.h b/gsk/gskvulkancrossfadepipelineprivate.h new file mode 100644 index 0000000000..da5e820365 --- /dev/null +++ b/gsk/gskvulkancrossfadepipelineprivate.h @@ -0,0 +1,35 @@ +#ifndef __GSK_VULKAN_CROSS_FADE_PIPELINE_PRIVATE_H__ +#define __GSK_VULKAN_CROSS_FADE_PIPELINE_PRIVATE_H__ + +#include + +#include "gskvulkanpipelineprivate.h" + +G_BEGIN_DECLS + +typedef struct _GskVulkanCrossFadePipelineLayout GskVulkanCrossFadePipelineLayout; + +#define GSK_TYPE_VULKAN_CROSS_FADE_PIPELINE (gsk_vulkan_cross_fade_pipeline_get_type ()) + +G_DECLARE_FINAL_TYPE (GskVulkanCrossFadePipeline, gsk_vulkan_cross_fade_pipeline, GSK, VULKAN_CROSS_FADE_PIPELINE, GskVulkanPipeline) + +GskVulkanPipeline * gsk_vulkan_cross_fade_pipeline_new (GdkVulkanContext *context, + VkPipelineLayout layout, + const char *shader_name, + VkRenderPass render_pass); + +gsize gsk_vulkan_cross_fade_pipeline_count_vertex_data (GskVulkanCrossFadePipeline *pipeline); +void gsk_vulkan_cross_fade_pipeline_collect_vertex_data (GskVulkanCrossFadePipeline *pipeline, + guchar *data, + const graphene_rect_t *bounds, + const graphene_rect_t *start_bounds, + const graphene_rect_t *end_bounds, + double progress); +gsize gsk_vulkan_cross_fade_pipeline_draw (GskVulkanCrossFadePipeline *pipeline, + VkCommandBuffer command_buffer, + gsize offset, + gsize n_commands); + +G_END_DECLS + +#endif /* __GSK_VULKAN_CROSS_FADE_PIPELINE_PRIVATE_H__ */ diff --git a/gsk/gskvulkanpipelineprivate.h b/gsk/gskvulkanpipelineprivate.h index 33660e1ecc..cd41f822b3 100644 --- a/gsk/gskvulkanpipelineprivate.h +++ b/gsk/gskvulkanpipelineprivate.h @@ -32,7 +32,6 @@ gsk_vulkan_handle_result (VkResult res, #define GSK_VK_CHECK(func, ...) gsk_vulkan_handle_result (func (__VA_ARGS__), G_STRINGIFY (func)) - GskVulkanPipeline * gsk_vulkan_pipeline_new (GType pipeline_type, GdkVulkanContext *context, VkPipelineLayout layout, diff --git a/gsk/gskvulkanrender.c b/gsk/gskvulkanrender.c index e21bef67f2..06b622db59 100644 --- a/gsk/gskvulkanrender.c +++ b/gsk/gskvulkanrender.c @@ -16,6 +16,7 @@ #include "gskvulkanboxshadowpipelineprivate.h" #include "gskvulkancolorpipelineprivate.h" #include "gskvulkancolortextpipelineprivate.h" +#include "gskvulkancrossfadepipelineprivate.h" #include "gskvulkaneffectpipelineprivate.h" #include "gskvulkanlineargradientpipelineprivate.h" #include "gskvulkantextpipelineprivate.h" @@ -388,6 +389,9 @@ gsk_vulkan_render_get_pipeline (GskVulkanRender *self, { "blend", 1, gsk_vulkan_color_text_pipeline_new }, { "blend-clip", 1, gsk_vulkan_color_text_pipeline_new }, { "blend-clip-rounded", 1, gsk_vulkan_color_text_pipeline_new }, + { "crossfade", 2, gsk_vulkan_cross_fade_pipeline_new }, + { "crossfade-clip", 2, gsk_vulkan_cross_fade_pipeline_new }, + { "crossfade-clip-rounded", 2, gsk_vulkan_cross_fade_pipeline_new }, }; g_return_val_if_fail (type < GSK_VULKAN_N_PIPELINES, NULL); diff --git a/gsk/gskvulkanrenderpass.c b/gsk/gskvulkanrenderpass.c index 9fe3764323..866a4eaa73 100644 --- a/gsk/gskvulkanrenderpass.c +++ b/gsk/gskvulkanrenderpass.c @@ -13,6 +13,7 @@ #include "gskvulkanclipprivate.h" #include "gskvulkancolorpipelineprivate.h" #include "gskvulkancolortextpipelineprivate.h" +#include "gskvulkancrossfadepipelineprivate.h" #include "gskvulkaneffectpipelineprivate.h" #include "gskvulkanlineargradientpipelineprivate.h" #include "gskvulkantextpipelineprivate.h" @@ -26,6 +27,7 @@ typedef union _GskVulkanOp GskVulkanOp; typedef struct _GskVulkanOpRender GskVulkanOpRender; typedef struct _GskVulkanOpText GskVulkanOpText; +typedef struct _GskVulkanOpCrossFade GskVulkanOpCrossFade; typedef struct _GskVulkanOpPushConstants GskVulkanOpPushConstants; typedef enum { @@ -35,8 +37,6 @@ typedef enum { GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP, GSK_VULKAN_OP_SURFACE, GSK_VULKAN_OP_TEXTURE, - GSK_VULKAN_OP_TEXT, - GSK_VULKAN_OP_COLOR_TEXT, GSK_VULKAN_OP_COLOR, GSK_VULKAN_OP_LINEAR_GRADIENT, GSK_VULKAN_OP_OPACITY, @@ -45,8 +45,13 @@ typedef enum { GSK_VULKAN_OP_BORDER, GSK_VULKAN_OP_INSET_SHADOW, GSK_VULKAN_OP_OUTSET_SHADOW, + /* GskVulkanOpText */ + GSK_VULKAN_OP_TEXT, + GSK_VULKAN_OP_COLOR_TEXT, + /* GskVulkanOpCrossFade */ + GSK_VULKAN_OP_CROSS_FADE, /* GskVulkanOpPushConstants */ - GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS + GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS, } GskVulkanOpType; struct _GskVulkanOpRender @@ -76,6 +81,20 @@ struct _GskVulkanOpText guint num_glyphs; /* number of *non-empty* glyphs (== instances) we render */ }; +struct _GskVulkanOpCrossFade +{ + GskVulkanOpType type; + GskRenderNode *node; /* node that's the source of this op */ + GskVulkanPipeline *pipeline; /* pipeline to use */ + GskRoundedRect clip; /* clip rect (or random memory if not relevant) */ + GskVulkanImage *start; /* source images to render */ + GskVulkanImage *end; + gsize vertex_offset; /* offset into vertex buffer */ + gsize vertex_count; /* number of vertices */ + gsize descriptor_set_start; /* indices into descriptor sets array */ + gsize descriptor_set_end; +}; + struct _GskVulkanOpPushConstants { GskVulkanOpType type; @@ -87,8 +106,9 @@ union _GskVulkanOp { GskVulkanOpType type; GskVulkanOpRender render; - GskVulkanOpPushConstants constants; GskVulkanOpText text; + GskVulkanOpCrossFade crossfade; + GskVulkanOpPushConstants constants; }; struct _GskVulkanRenderPass @@ -161,10 +181,23 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass *self, case GSK_REPEAT_NODE: case GSK_SHADOW_NODE: case GSK_BLEND_NODE: - case GSK_CROSS_FADE_NODE: default: FALLBACK ("Unsupported node '%s'\n", node->node_class->type_name); + case GSK_CROSS_FADE_NODE: + if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds)) + pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE; + else if (constants->clip.type == GSK_VULKAN_CLIP_RECT) + pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP; + else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR) + pipeline_type = GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP_ROUNDED; + else + FALLBACK ("Cross fade nodes can't deal with clip type %u\n", constants->clip.type); + op.type = GSK_VULKAN_OP_CROSS_FADE; + op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type); + g_array_append_val (self->render_ops, op); + return; + case GSK_INSET_SHADOW_NODE: if (gsk_inset_shadow_node_get_blur_radius (node) > 0) FALLBACK ("Blur support not implemented for inset shadows\n"); @@ -707,6 +740,24 @@ gsk_vulkan_render_pass_upload (GskVulkanRenderPass *self, } break; + case GSK_VULKAN_OP_CROSS_FADE: + { + GskRenderNode *start = gsk_cross_fade_node_get_start_child (op->crossfade.node); + GskRenderNode *end = gsk_cross_fade_node_get_end_child (op->crossfade.node); + + op->crossfade.start = gsk_vulkan_render_pass_get_node_as_texture (self, + render, + uploader, + start, + &start->bounds); + op->crossfade.end = gsk_vulkan_render_pass_get_node_as_texture (self, + render, + uploader, + end, + &end->bounds); + } + break; + default: g_assert_not_reached (); case GSK_VULKAN_OP_COLOR: @@ -787,6 +838,11 @@ gsk_vulkan_render_pass_count_vertex_data (GskVulkanRenderPass *self) n_bytes += op->render.vertex_count; break; + case GSK_VULKAN_OP_CROSS_FADE: + op->crossfade.vertex_count = gsk_vulkan_cross_fade_pipeline_count_vertex_data (GSK_VULKAN_CROSS_FADE_PIPELINE (op->crossfade.pipeline)); + n_bytes += op->crossfade.vertex_count; + break; + default: g_assert_not_reached (); case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS: @@ -977,6 +1033,22 @@ gsk_vulkan_render_pass_collect_vertex_data (GskVulkanRenderPass *self, } break; + case GSK_VULKAN_OP_CROSS_FADE: + { + GskRenderNode *start = gsk_cross_fade_node_get_start_child (op->crossfade.node); + GskRenderNode *end = gsk_cross_fade_node_get_end_child (op->crossfade.node); + + op->crossfade.vertex_offset = offset + n_bytes; + gsk_vulkan_cross_fade_pipeline_collect_vertex_data (GSK_VULKAN_CROSS_FADE_PIPELINE (op->crossfade.pipeline), + data + n_bytes + offset, + &op->crossfade.node->bounds, + &start->bounds, + &end->bounds, + gsk_cross_fade_node_get_progress (op->crossfade.node)); + n_bytes += op->crossfade.vertex_count; + } + break; + default: g_assert_not_reached (); case GSK_VULKAN_OP_PUSH_VERTEX_CONSTANTS: @@ -1017,6 +1089,12 @@ gsk_vulkan_render_pass_reserve_descriptor_sets (GskVulkanRenderPass *self, case GSK_VULKAN_OP_COLOR_TEXT: op->text.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->text.source); break; + + case GSK_VULKAN_OP_CROSS_FADE: + op->crossfade.descriptor_set_start = gsk_vulkan_render_reserve_descriptor_set (render, op->crossfade.start); + op->crossfade.descriptor_set_end = gsk_vulkan_render_reserve_descriptor_set (render, op->crossfade.end); + break; + default: g_assert_not_reached (); case GSK_VULKAN_OP_COLOR: @@ -1320,6 +1398,40 @@ gsk_vulkan_render_pass_draw (GskVulkanRenderPass *self, pipeline_layout[i]); break; + case GSK_VULKAN_OP_CROSS_FADE: + if (current_pipeline != op->crossfade.pipeline) + { + current_pipeline = op->crossfade.pipeline; + vkCmdBindPipeline (command_buffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + gsk_vulkan_pipeline_get_pipeline (current_pipeline)); + vkCmdBindVertexBuffers (command_buffer, + 0, + 1, + (VkBuffer[1]) { + gsk_vulkan_buffer_get_buffer (vertex_buffer) + }, + (VkDeviceSize[1]) { op->crossfade.vertex_offset }); + current_draw_index = 0; + } + + vkCmdBindDescriptorSets (command_buffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + gsk_vulkan_pipeline_get_pipeline_layout (current_pipeline), + 0, + 2, + (VkDescriptorSet[2]) { + gsk_vulkan_render_get_descriptor_set (render, op->crossfade.descriptor_set_start), + gsk_vulkan_render_get_descriptor_set (render, op->crossfade.descriptor_set_end) + }, + 0, + NULL); + + current_draw_index += gsk_vulkan_cross_fade_pipeline_draw (GSK_VULKAN_CROSS_FADE_PIPELINE (current_pipeline), + command_buffer, + current_draw_index, 1); + break; + default: g_assert_not_reached (); break; diff --git a/gsk/gskvulkanrenderprivate.h b/gsk/gskvulkanrenderprivate.h index f372282d25..6739bb5941 100644 --- a/gsk/gskvulkanrenderprivate.h +++ b/gsk/gskvulkanrenderprivate.h @@ -40,6 +40,9 @@ typedef enum { GSK_VULKAN_PIPELINE_COLOR_TEXT, GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP, GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP_ROUNDED, + GSK_VULKAN_PIPELINE_CROSS_FADE, + GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP, + GSK_VULKAN_PIPELINE_CROSS_FADE_CLIP_ROUNDED, /* add more */ GSK_VULKAN_N_PIPELINES } GskVulkanPipelineType; diff --git a/gsk/meson.build b/gsk/meson.build index cd18151287..072c140da3 100644 --- a/gsk/meson.build +++ b/gsk/meson.build @@ -62,6 +62,7 @@ if have_vulkan 'gskvulkanclip.c', 'gskvulkancolorpipeline.c', 'gskvulkancolortextpipeline.c', + 'gskvulkancrossfadepipeline.c', 'gskvulkancommandpool.c', 'gskvulkaneffectpipeline.c', 'gskvulkanglyphcache.c', diff --git a/gsk/resources/vulkan/crossfade-clip-rounded.frag.spv b/gsk/resources/vulkan/crossfade-clip-rounded.frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..58eb4f78d818e99aa73b55ef57fbbbf189164a2b GIT binary patch literal 8720 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 literal 0 HcmV?d00001 diff --git a/gsk/resources/vulkan/crossfade-clip-rounded.vert.spv b/gsk/resources/vulkan/crossfade-clip-rounded.vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..9ed91e1326b37a447c99105d65413e3e4ff73c42 GIT binary patch literal 5840 zcmZ9OiFaL96~=FyyrdJQEtD!^O)V-yt*C`kDo`vnEd-ic#MzkUy(AaY_riNGrO40% zQV<751(^gz1?PDL6ciMkaMmh_K&}1-x?D?^zu(Q>=^>l-arXC}efHUBpL1W@F>`r$ zmd)V5gR*~RleRFM3D2^*SywUk_HFH3*=ko;t~%~mBj#rvMW8VU^PkoUwh!iY{U*2= z>;X4`d%^wSaj+Nc1N%V-|IK8)n?#-2oUFHRpm+1;-o6b3L*wHEt@Z_DwSlp`UK^<9 z&Du~q-%&GeRuY%jhsGwVX+VXDw3bTNoy}v9yxy)gTVy$E$MCAPBFif5KZm(Npg)&! zTj5u-1&l*u`FIgtXr0ALEd)w@XSRf~F+AL=wOa*W4R6+36JtbF=$*OxCt9QH8}(Lu zuufEl+F9th+4ddd@X0uP>3##-8WZ(uYf862g?@fsZI7yV7wf%&LLaT=Bcny?qJ}E^ zID0Y_d_+Fj9Nb>=d>S8zr)To+^7@;KQ+h^gKCr$cJ73=Lyj{f|kBkkRQ){+sJ2%y< zwVjjaem^nj{k7)g6tp;xy5?M?mACUooje`IJ5hH(-%Den&HN<)D4gs?iSBt1oMtxL zAr|YpiZ_oonZD-V9$?jvmRr+y;F}d>!@f(TpZD`9Uhv#X0kj49pINyeG>p*C} z3$^}4^G&F|2lUcc_b{%P{k_+vK$H7@`reNQ=8U^h(_F6>>%EtBz2CIl+RSH9PZ;dL?gfF;D+BY7w2;s3K3)x0p+j0x?ClBpjFU;$8f-n!Ic?M{5P%|tI^ya1>P%^pPT`|#7)3*l4m-f2r$+;zvsijb>wjF8sI+0Sj)AH z*MU92TC7!WT-0$RzI8a~Tb4U#zK?;lw>OoVx@KJwdo#ZG9e4I|d^MpNdpR}P(_4VK zjEVKP;-~9xgR64%;A$e)N9>(w>0Woi)kMU`UY|rWmoafK zpTf5WEwsDw)jVftpT>8+7TRa<)r^Zf{VcvY&EXnjybr%W=c4Y<;rsg%J^nntn$XM{ zv0uPXW4{Pj6LH3f{SumcMcyyts|n4#@jZM6-(1GT_wZGGYjG}eehoj}|LbryF@67U zpr!kN6RsvAHunD(nz@XLo_-tO8nn>9gRhp}$9Lhb*COtF_-g5Wd>?L3bGXJB@5A3e z=i-bH;NK6TZ$H3S6Iyy7KZK{T55m<%oH6n~gqHT>M{qTvnK%0JV|;TN6Zi2jzO^_P zIUm7K_x}l8O-$ear)cT^kHXbN#K!)Qp_$8==;_b!tw9Uz=lE*Y9@;PPU9W}qOMErs z;`{g&zB$d|8e_Z<|Nb}^XZ$t3cNF*W8+c%W${3B40zWfQ_oa%8ef5x{a=dAy6MzyHvFZiA*>i;Xgn$XhvpMa;aPr}v2 z^!opXme&6i-1^m{{=eft1)~0^@y)3o^*@7eP0m^WUPd)@bTR%D><7;6EBXJZ`UK#= zPrA|O0c|!|P24QTIf*|P-+#9p#2EihS&i@7=+jH^T@!uk!B-Pn+NWjkH1?%%HKC=k z%i(G4k#IE;J&j(x49#4|#M^y2eh<(>dj)+sdmeyoDKUW>Tn@YT|O91l0AIb36m{jf&o;*2NYr}wx9t|qkfj3>g=Gp>cJ3C-Af zygtA2*O%P8FsHGx=SleKo+lS`&L8Mi#GZnd?zs-GCZeyg=c#Dc;M*|gIuJd21HLtB zp{>V{Izu}R%{*FY8}K7{ytg-^nbRDuF~HGePkpJUuoa`mWTD}GwT*>E+X zrS-lUp2nU7R})chj6G3Le}fmmwfP`^gAc~Hj|&;&cXtH8JK=fBx literal 0 HcmV?d00001 diff --git a/gsk/resources/vulkan/crossfade-clip.frag.spv b/gsk/resources/vulkan/crossfade-clip.frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..76fa8b02dcb5843479c0c6d716e64dc2350faa7a GIT binary patch literal 1780 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 literal 0 HcmV?d00001 diff --git a/gsk/resources/vulkan/crossfade-rect.vert.spv b/gsk/resources/vulkan/crossfade-rect.vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..9ed91e1326b37a447c99105d65413e3e4ff73c42 GIT binary patch literal 5840 zcmZ9OiFaL96~=FyyrdJQEtD!^O)V-yt*C`kDo`vnEd-ic#MzkUy(AaY_riNGrO40% zQV<751(^gz1?PDL6ciMkaMmh_K&}1-x?D?^zu(Q>=^>l-arXC}efHUBpL1W@F>`r$ zmd)V5gR*~RleRFM3D2^*SywUk_HFH3*=ko;t~%~mBj#rvMW8VU^PkoUwh!iY{U*2= z>;X4`d%^wSaj+Nc1N%V-|IK8)n?#-2oUFHRpm+1;-o6b3L*wHEt@Z_DwSlp`UK^<9 z&Du~q-%&GeRuY%jhsGwVX+VXDw3bTNoy}v9yxy)gTVy$E$MCAPBFif5KZm(Npg)&! zTj5u-1&l*u`FIgtXr0ALEd)w@XSRf~F+AL=wOa*W4R6+36JtbF=$*OxCt9QH8}(Lu zuufEl+F9th+4ddd@X0uP>3##-8WZ(uYf862g?@fsZI7yV7wf%&LLaT=Bcny?qJ}E^ zID0Y_d_+Fj9Nb>=d>S8zr)To+^7@;KQ+h^gKCr$cJ73=Lyj{f|kBkkRQ){+sJ2%y< zwVjjaem^nj{k7)g6tp;xy5?M?mACUooje`IJ5hH(-%Den&HN<)D4gs?iSBt1oMtxL zAr|YpiZ_oonZD-V9$?jvmRr+y;F}d>!@f(TpZD`9Uhv#X0kj49pINyeG>p*C} z3$^}4^G&F|2lUcc_b{%P{k_+vK$H7@`reNQ=8U^h(_F6>>%EtBz2CIl+RSH9PZ;dL?gfF;D+BY7w2;s3K3)x0p+j0x?ClBpjFU;$8f-n!Ic?M{5P%|tI^ya1>P%^pPT`|#7)3*l4m-f2r$+;zvsijb>wjF8sI+0Sj)AH z*MU92TC7!WT-0$RzI8a~Tb4U#zK?;lw>OoVx@KJwdo#ZG9e4I|d^MpNdpR}P(_4VK zjEVKP;-~9xgR64%;A$e)N9>(w>0Woi)kMU`UY|rWmoafK zpTf5WEwsDw)jVftpT>8+7TRa<)r^Zf{VcvY&EXnjybr%W=c4Y<;rsg%J^nntn$XM{ zv0uPXW4{Pj6LH3f{SumcMcyyts|n4#@jZM6-(1GT_wZGGYjG}eehoj}|LbryF@67U zpr!kN6RsvAHunD(nz@XLo_-tO8nn>9gRhp}$9Lhb*COtF_-g5Wd>?L3bGXJB@5A3e z=i-bH;NK6TZ$H3S6Iyy7KZK{T55m<%oH6n~gqHT>M{qTvnK%0JV|;TN6Zi2jzO^_P zIUm7K_x}l8O-$ear)cT^kHXbN#K!)Qp_$8==;_b!tw9Uz=lE*Y9@;PPU9W}qOMErs z;`{g&zB$d|8e_Z<|Nb}^XZ$t3cNF*W8+c%W${3B40zWfQ_oa%8ef5x{a=dAy6MzyHvFZiA*>i;Xgn$XhvpMa;aPr}v2 z^!opXme&6i-1^m{{=eft1)~0^@y)3o^*@7eP0m^WUPd)@bTR%D><7;6EBXJZ`UK#= zPrA|O0c|!|P24QTIf*|P-+#9p#2EihS&i@7=+jH^T@!uk!B-Pn+NWjkH1?%%HKC=k z%i(G4k#IE;J&j(x49#4|#M^y2eh<(>dj)+sdmeyoDKUW>Tn@YT|O91l0AIb36m{jf&o;*2NYr}wx9t|qkfj3>g=Gp>cJ3C-Af zygtA2*O%P8FsHGx=SleKo+lS`&L8Mi#GZnd?zs-GCZeyg=c#Dc;M*|gIuJd21HLtB zp{>V{Izu}R%{*FY8}K7{ytg-^nbRDuF~HGePkpJUuoa`mWTD}GwT*>E+X zrS-lUp2nU7R})chj6G3Le}fmmwfP`^gAc~Hj|&;&cXtH8JK=fBx literal 0 HcmV?d00001 diff --git a/gsk/resources/vulkan/crossfade.frag b/gsk/resources/vulkan/crossfade.frag new file mode 100644 index 0000000000..8293b1d5d8 --- /dev/null +++ b/gsk/resources/vulkan/crossfade.frag @@ -0,0 +1,21 @@ +#version 420 core + +#include "clip.frag.glsl" + +layout(location = 0) in vec2 inPos; +layout(location = 1) in vec2 inStartTexCoord; +layout(location = 2) in vec2 inEndTexCoord; +layout(location = 3) in float inProgress; + +layout(set = 0, binding = 0) uniform sampler2D startTexture; +layout(set = 1, binding = 0) uniform sampler2D endTexture; + +layout(location = 0) out vec4 color; + +void main() +{ + vec4 start = texture (startTexture, inStartTexCoord); + vec4 end = texture (endTexture, inEndTexCoord); + + color = clip (inPos, mix (start, end, inProgress)); +} diff --git a/gsk/resources/vulkan/crossfade.frag.spv b/gsk/resources/vulkan/crossfade.frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..76fa8b02dcb5843479c0c6d716e64dc2350faa7a GIT binary patch literal 1780 zcmY+F>rWFw6vYSV7UXSE9-_DfAK(KO!AFS3gpl%~2~9BZW3BB%Hz~WD-EGzX$3N09 z8qaUK)2u@-Gw0lM@7%dF3saLj)5c8bXTcnq(YR?Qg^igrRXf)k7mfWa@9rNSy+pBS zrmPUnl9@FX&DeE2jBwnM`LYMHhq67{vSQF^Gp(kygE7C9prZJCqg6jYuQyIxog`^x z`OkjP>W5L#>V|31$-`lQZl>CJqhjRjsO; zec77oV^1(XUwB3{9ESgfX8gQ${IiBzAYPc;2I&!WS zBDmuMbB_%C8=8q_U;JS15zgt|9XP*V_=%@CoS&NUgSkgIr{^BYhkmzMa|Zli?iK&K z@GH&aq9n?xuZUJ^T*KzCWh(_?T5e)uov`!w?Pxkf}7wrxC55(XEF0%B zWZCd|eRA9M$lk-)`YdNQDO1kZFgHg=+Of_OdzEp~g90hI7LF8m;jyIK{O(A?9)2dH?H;bFREvn~6ItWj>Z# zqdM#I-UXRty+zU3~?-}KOhrRs0lvzz|hA%5@b^TW|>u;`g@Kwycz_Fv?{>td{0NndC zM$P=InO##qTyVc@5zVeGv?O@z-n>@2%-EPU3()bt5$L&4QU+lVcn)0X9R z+y{3La~LDE^|fa2a}n@PtXb|mRCC>4yJoH4$@X0Tf8DpKue$Ma-)+S2!uH(8Z=yfG zSM!7se9Qiu;aP(BCVUI_)`aU{UcmkROym81lpkd`-?MM(2z#k* z2EG^9dJBGtYFv95_*>NrT(>T@hzmmL ze1j*b!}qrvShu=9?)3yvzmAW54=|_t)k1p`+nQXne(z1qyuKm-4fkF7M$PMcdKRe1 zK1Z;PJ41~9JesfZ7bCP|*!p?iLGHr4I}Y@9&F|iC`W87{I|1D1cy5>S_j?lCZ^v4! zRjyyu@dCDWxYoxkcg=jKKzg^Q3r*dT_Tfdi{f?f!gsmnV`d%yUuOHi7`ovx@W2f=2 zz|}gE`8#A7{<01*CJ;XJKetqR}%~OA3;m^ABC%l@QwY)(9ESz z+-V)#8XTd$kF93yp?!dDyd$)6Y&HF&9~0Q-G>0+z*bjgIT#GYKVmCqD+lSa{!eP$v zZDFUrZMd3#XD<}`;fSAhL!FuN9KyoPO$ zq90#is|klW!}mIN>iZ>JO~e`X-46c>>;V40?_$0I)&O;VRx*DL)Z<>h!8WIQ^yOP@ zYjVx{XPMQarth#lQ`G-GwwiFH_5T1*eSd_jiG}swLQCua32y!BQUA}_>QVnM*ydD^ z`hUf?CfBV0CbOD3x|#m~cYtfR3;qvP9|ZpYqz7#Ua4Z7{@LS5f9Qc2gyO`rH?l1Iz I(Y4L-A7!CLqW}N^ literal 0 HcmV?d00001 diff --git a/gsk/resources/vulkan/meson.build b/gsk/resources/vulkan/meson.build index 1007858525..6e61885e65 100644 --- a/gsk/resources/vulkan/meson.build +++ b/gsk/resources/vulkan/meson.build @@ -12,6 +12,7 @@ gsk_private_vulkan_fragment_shaders = [ 'border.frag', 'color.frag', 'color-matrix.frag', + 'crossfade.frag', 'inset-shadow.frag', 'linear.frag', 'mask.frag', @@ -24,6 +25,7 @@ gsk_private_vulkan_vertex_shaders = [ 'border.vert', 'color.vert', 'color-matrix.vert', + 'crossfade.vert', 'inset-shadow.vert', 'linear.vert', 'mask.vert', -- 2.30.2